# S_DES类
"""
明密文：8bits
key：10bits
"""
class S_DES_Binary:
    P_Box_10 = [3, 5, 2, 7, 4, 10, 1, 9, 8, 6]
    P_Box_8 = [6, 3, 7, 4, 8, 5, 10, 9]
    P_Box_IP = [2, 6, 3, 1, 4, 8, 5, 7]
    P_Box_IP_Reverse = [4, 1, 3, 5, 7, 2, 8, 6]
    LeftShift_1 = [2,3,4,5,1]
    LeftShift_2 = [3,4,5,1,2]
    EP_Box = [4, 1, 2, 3, 2, 3, 4, 1]
    SP_Box = [2, 4, 3, 1]
    S_Box_1 = [["01", "00", "11", "10"],
             ["11", "10", "01", "00"],
             ["00", "10", "01", "11"],
             ["11", "01", "00", "10"]]
    S_Box_2 = [["00", "01", "10", "11"],
               ["10", "11", "01", "00"],
               ["11", "00", "01", "10"],
               ["10", "01", "00", "11"]]

    def __init__(self, k):
        self.plainText = ""
        self.ciperText = ""
        self.key = k
        self.currentText = ""
        self.round_Keys = []
        self.Generate_Round_Keys(self.key)
    def changePlainText(self, p):
        self.plainText = p
    def changeCipherText(self, c):
        self.ciperText = c
    def Permutation(self, Text, PBox):
        #置换操作
        currText = ""
        for i in PBox:
            currText = currText + Text[i - 1]
        return currText
    def Substution(self,text,SBox):
        #替换操作
        L = int(text[0])*2+int(text[3])
        R = int(text[1])*2+int(text[2])
        return SBox[L][R]

    def Function_Round_Key(self,roundKey):
        L = self.currentText[:4]
        R = self.currentText[4:]
        new_R = self.Permutation(R,self.EP_Box)
        new_R = self.XOR(new_R,roundKey)
        #将R分成两部分 分别SBOX
        new_R_1 = self.Substution(new_R[:4],self.S_Box_1)
        new_R_2 = self.Substution(new_R[4:],self.S_Box_2)
        new_R = new_R_1 + new_R_2
        new_R = self.Permutation(new_R,self.SP_Box)
        new_L = self.XOR(L,new_R)
        return new_L + R
    def XOR(self,s1,s2):
        ans = ""
        for i in range(0,len(s1)):
            if s1[i]!=s2[i]:
                ans += "1"
            else:
                ans += "0"
        return ans
    def Generate_Round_Keys(self, key):
        currentKey = self.Permutation(key, self.P_Box_10)
        currKey1 = self.Permutation(currentKey[:5],self.LeftShift_1)+self.Permutation(currentKey[5:],self.LeftShift_1)
        currKey2 = self.Permutation(currKey1[:5],self.LeftShift_2)+self.Permutation(currKey1[5:],self.LeftShift_2)
        roundKey1 = self.Permutation(currKey1,self.P_Box_8)
        roundKey2 = self.Permutation(currKey2,self.P_Box_8)
        self.round_Keys.append(roundKey1)
        self.round_Keys.append(roundKey2)
    def Decryption(self,c):
        #解密
        self.changeCipherText(c)
        self.currentText = self.Permutation(self.ciperText, self.P_Box_IP)
        self.currentText = self.Function_Round_Key(self.round_Keys[1])
        self.Switch()
        self.currentText = self.Function_Round_Key(self.round_Keys[0])
        self.plainText = self.Permutation(self.currentText, self.P_Box_IP_Reverse)

    def Encryption(self,p):
        #加密
        self.changePlainText(p)
        self.currentText = self.Permutation(self.plainText, self.P_Box_IP)
        self.currentText = self.Function_Round_Key(self.round_Keys[0])
        self.Switch()
        self.currentText = self.Function_Round_Key(self.round_Keys[1])
        self.ciperText = self.Permutation(self.currentText, self.P_Box_IP_Reverse)

    def Switch(self):
        L = self.currentText[:4]
        R = self.currentText[4:]
        self.currentText = R + L
def AsciiEncryption(PlainText, Key):
    DES = S_DES_Binary(Key)
    Cipher = ""
    for c in PlainText:
        PlainTextBinary = bin(ord(c))[2:]  # 去掉0b前缀
        if len(PlainTextBinary) != 8:
            PlainTextBinary = "0"*(8-len(PlainTextBinary)) + PlainTextBinary  # 向前补位
        DES.Encryption(PlainTextBinary)
        currentCipher = "0b" + DES.ciperText
        ascii_code = int(currentCipher, 2)
        Cipher += chr(ascii_code)
    return Cipher
def AsciiDencryption(CipherText, Key):
    DES = S_DES_Binary(Key)
    PlainText = ""
    for c in CipherText:
        CipherTextBinary = bin(ord(c))[2:]  # 去掉0b前缀
        if len(CipherTextBinary) != 8:
            CipherTextBinary = "0"*(8-len(CipherTextBinary)) + CipherTextBinary  # 向前补位
        DES.Decryption(CipherTextBinary)
        currentPlain = "0b" + DES.plainText
        ascii_code = int(currentPlain, 2)
        PlainText += chr(ascii_code)
    return PlainText
#测试入口
if __name__ == "__main__":
    isAscii = True
    if not isAscii:
        PlainText = str(input("请输入明文:"))
        Key = str(input("请输入秘钥:"))
        if (len(PlainText) != 8) or (len(Key) !=10):
            assert ("明文长度不足8位/秘钥长度不足10位")
        DES = S_DES_Binary(Key)
        DES.Encryption(PlainText)
        print(DES.ciperText)
        print('*'*60)
        DES.Decryption(DES.ciperText)
        print(DES.plainText)
    else:
        PlainText = str(input("请输入ASCII明文:"))
        Key = str(input("请输入秘钥:"))
        Cipher = AsciiEncryption(PlainText,Key)
        print(Cipher)
        Plain = AsciiDencryption(Cipher,Key)
        print(Plain)
